package com.guan.core;

import com.guan.core.annotation.Autowired;
import com.guan.core.annotation.Bean;
import com.guan.core.annotation.Controller;
import com.guan.core.annotation.RequestMapping;
import com.guan.core.entity.BeanEntity;
import com.guan.core.entity.Property;
import com.guan.core.util.XMLUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Bean容器，针对注解实现
 * Created by Administrator on 2018/1/15 0015.
 */
@SuppressWarnings("all")
public class BeanContext {
    /**
     * 扫描到的所有类 key为完整的类名，value 为class的实例
     */
    private Map<String, Class<?>> classs;
    /**
     * 存放单列的实例bean对象 key是id--注解bean的value
     */
    private Map<String, Object> beans = new HashMap<String, Object>();
    // 存放多例的实例bean对象，注解对象
    private Map<String, BeanEntity> propertys = new HashMap<String, BeanEntity>();
    /**
     * 存放控制器的实例 key是类名
     */
    private Map<String, Object> controllers = new HashMap<String, Object>();
    /**
     * 存放路径的实例 key是路径
     */
    private Map<String, Method> reqs = new HashMap<String, Method>();

    /**
     * 防止空构造new出来
     *
     * @param classs
     */
    public BeanContext(Map<String, Class<?>> classs) {
        this.classs = classs;
        init();
    }

    /**
     * 容器初始化
     */
    private void init() {
        XMLUtil.log("*************beanContext容器初始化开始**********");
        Iterator<String> itor = classs.keySet().iterator();
        try {
            while (itor.hasNext()) {
                String key = itor.next();
                Class clazz = classs.get(key);
                //判断是否有注解，是否为bean 不是与bean有关的注解就是与controller有关的注解
                if (clazz.isAnnotationPresent(Bean.class)) {
                    initBean(clazz);
                } else if (clazz.isAnnotationPresent(Controller.class)) {
                    initController(clazz);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        XMLUtil.log("*************beanContext容器初始化结束**********");
    }

    /**
     * bean实例的初始化操作
     *
     * @param clazz
     * @return
     */
    private Object initBean(Class clazz) {
        Object object = null;
        try {
            //拿bean注解
            Bean bean = (Bean) clazz.getAnnotation(Bean.class);
            if (bean.single()) {
                String id = bean.value(); //bean的唯一标志
                if (beans.containsKey(id)) {//如果存在（已经被初始化了），直接返回
                    return beans.get(id);
                }
                object = clazz.newInstance();
                Field[] files = clazz.getDeclaredFields();
                for (Field field : files) {
                    //判断是否自动注入
                    if (field.isAnnotationPresent(Autowired.class)) {
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String propName = autowired.value();
                        //从bean容器中取对应的实例
                        Object o = getBean(propName);
                        if(o==null){
                            //拿到这个属性的Class
                            Class clazzF = field.getType();
                            initBean(clazzF);
                            o = getBean(propName);
                        }
                        field.setAccessible(true);
                        field.set(object, o);
                    }
                }
                //放入单例实例中
                beans.put(bean.value(), object);
            } else {
                BeanEntity beanEntity = new BeanEntity();
                beanEntity.setId(bean.value());
                beanEntity.setClazz(clazz);
                Field[] files = clazz.getDeclaredFields();
                for (Field field : files) {
                    //判断是否自动注入
                    if (field.isAnnotationPresent(Autowired.class)) {
                        Property property = new Property();
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String propName = autowired.value();
                        property.setRef(propName);
                        property.setField(field);
                        beanEntity.addProperty(property);
                    }
                }
                propertys.put(bean.value(),beanEntity);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return object;
    }

    /**
     * 初始化controller
     *
     * @param clazz
     */
    public void initController(Class clazz) {
        String className = clazz.getName();//类的全路径
        String path = ""; //映射的路径
        String pPath = "";//类上边的映射路径
        boolean flag = false;
        try {
            if (clazz.isAnnotationPresent(RequestMapping.class)) {
                //类名上的路径
                pPath = ((RequestMapping) clazz.getAnnotation(RequestMapping.class)).value();
            }
            //取方法上的路径
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    reqs.put(pPath+method.getDeclaredAnnotation(RequestMapping.class).value(),method);
                    flag = true;
                }
            }
            if(flag){
                Object obj  = clazz.newInstance();
                Field[] fields = clazz.getDeclaredFields();
                for(Field field : fields){
                    //判断是否需要自动注入
                    if(field.isAnnotationPresent(Autowired.class)){
                        Autowired auto = (Autowired)field.getAnnotation(Autowired.class);
                        String propName = auto.value();
                        //从Bean容器中去取对应的实例
                        Object o = getBean(propName);
                        if(o==null){
                            //拿到这个属性的Class
                            Class clazzF = field.getType();
                            initBean(clazzF);
                            o = getBean(propName);
                        }
                        field.setAccessible(true);
                        field.set(obj, o);
                    }
                }
                controllers.put(className,obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取bean实例
     *
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        //先通过单例拿
        Object instance = beans.get(beanName);
        if(null == instance) {
            //通过原型去拿
            BeanEntity b = propertys.get(beanName);
            try {
                Class<?> clazz = b.getClazz();
                instance = clazz.newInstance();
                for(Property pro:b.getProps()) {
                    //通过反射拿到所有的属性
                    Field field = pro.getField();
                    //开放修改权限
                    field.setAccessible(true);
                    field.set(instance, getBean(pro.getRef()));
                }
            } catch (Exception e) {

            }

        }
        return instance;
    }

    /**
     * 通过映射路径，直接拿到对应的方法
     * @param path
     * @return
     */
    public Method getExecMethod(String path){
        return reqs.get(path);
    }

    /**
     * 获取collector实例
     * @param className
     * @return
     */
    public BaseController getController(String className){
        return (BaseController)controllers.get(className);
    }
}
